package com.example.myapplication.widgets.chart;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

import com.example.myapplication.R;
import com.example.myapplication.widgets.CanvasUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 圆环统计图
 */
public class RingChartView extends View {

    // 每一项之间存在间隔
    private final int SpaceAngle = 2;
    private int mShowInfoCount = 5;
    private int mTitleLine = 1;

    private int mCircleRadius = 100; // 中间圆的半径
    private int mRingWidth = 30; // 圆环宽度
    private int mRingColor = Color.GREEN;
    private int mTextSize = 30;
    private int mTextColor = Color.BLACK;

    private Paint mPaint;
    private float mTotalValue;
    private List<RingBean> mData;
    private float mYInterval = 12; // 两个信息文字间Y轴间距

    public RingChartView(Context context) {
        this(context, null);
    }

    public RingChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RingChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public RingChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.RingChartView);
            mCircleRadius = typedArray.getDimensionPixelSize(R.styleable.RingChartView_circleRadius, mCircleRadius);
            mRingWidth = typedArray.getDimensionPixelSize(R.styleable.RingChartView_ringWidth, mRingWidth);
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.RingChartView_textSize, mTextSize);

            mRingColor = typedArray.getColor(R.styleable.RingChartView_ringColor, mRingColor);
            mTextColor = typedArray.getColor(R.styleable.RingChartView_textColor, mTextColor);
            typedArray.recycle();
        }

        mData = new ArrayList<>();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    public void clear() {
        mTotalValue = 0;
        mData.clear();
        invalidate();
    }

    public void setShowInfoCount(int showInfoCount) {
        mShowInfoCount = showInfoCount;
    }

    // 区分百分比和标题是两行还是一行展示
    public void setTitleLine(boolean isSingleLine) {
        mTitleLine = isSingleLine? 1 : 2;
    }

    public void addRingBean(RingBean bean) {
        mTotalValue += bean.value;
        if (mData.isEmpty() || mData.get(mData.size() - 1).value >= bean.value)
            mData.add(bean);
        else {
            for (int i = 0; i < mData.size(); i++) {
                if (mData.get(i).value < bean.value) {
                    mData.add(i, bean);
                    break;
                }
            }
        }
        invalidate();
    }

    public float getTotalValue() {
        return mTotalValue;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mData.isEmpty()) return;
        drawRing(canvas);
        drawInfo(canvas);
    }

    private void drawRing(Canvas canvas) {
        float left = getWidth() / 2f - mCircleRadius - mRingWidth / 2f;
        float top = getHeight() / 2f - mCircleRadius - mRingWidth / 2f;
        float right = left + mCircleRadius * 2 + mRingWidth;
        float bottom = top + mCircleRadius * 2 + mRingWidth;
        mPaint.setStrokeWidth(mRingWidth);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(mRingColor);

        if (mData.size() > 1) {
            float currentAngle = -90; // -90顶部0点位置开始
            float toAngle;
            for (RingBean datum : mData) {
                toAngle = (360 - mData.size() * SpaceAngle) * datum.value / mTotalValue;
                canvas.drawArc(left, top, right, bottom, currentAngle, toAngle, false, mPaint);
                Log.i("RingChartView", "from: " + currentAngle + " to: " + (currentAngle + toAngle));
                currentAngle = currentAngle + toAngle + SpaceAngle;
            }
        } else {
            canvas.drawArc(left, top, right, bottom, 0, 360, false, mPaint);
        }
    }

    private void drawInfo(Canvas canvas) {
        float preDrawInfoY;
        float preDrawInfoX = preDrawInfoY = 0;
        float currentAngle = -90; // -90顶部0点位置开始
        float toAngle, centerAngle;
        RingBean datum;
        double r = mCircleRadius + mRingWidth; // 外圆的半径
        double angleRadians;
        float x, y, abs;
        float textX, textY;
        Path path = new Path();
        for (int i = 0; i < mShowInfoCount; i++) {
            if (i >= mData.size()) break;
            datum = mData.get(i);
            // 先画线
            mPaint.setColor(mRingColor);
            mPaint.setStrokeWidth(4);
            mPaint.setStyle(Paint.Style.STROKE);

            toAngle = (360 - mData.size() * SpaceAngle) * datum.value / mTotalValue;
            centerAngle = (currentAngle + currentAngle + toAngle) / 2f;
            angleRadians = Math.toRadians(centerAngle); // 将角度转换为弧度
            Log.i("RingChart", "drawInfo from: " + currentAngle + " to: " + (currentAngle + toAngle));
            currentAngle = currentAngle + toAngle + SpaceAngle;

            x = (float) (r * Math.cos(angleRadians) + getWidth() / 2f);
            y = (float) (r * Math.sin(angleRadians) + getHeight() / 2f);
            path.moveTo(x, y);

            x = (float) ((r + 20) * Math.cos(angleRadians) + getWidth() / 2f);
            y = (float) ((r + 20) * Math.sin(angleRadians) + getHeight() / 2f);
            if (preDrawInfoX != 0 && preDrawInfoY != 0) {
                // 之前有画过信息数据，则需要判断，避免两次信息数据叠加在一起
                if (preDrawInfoX > getWidth() / 2f && x > getWidth() / 2f ||
                        preDrawInfoX <= getWidth() / 2f && x <= getWidth() / 2f) {
                    // 两次都是指向左边或都是指向右边，才存在叠加的可能
                    if (x > getWidth() / 2f && y < preDrawInfoY ||
                            x <= getWidth() / 2f && y > preDrawInfoY ||
                            Math.abs(y - preDrawInfoY) < (mPaint.getTextSize() + mYInterval) * mTitleLine) {
                        if (x > getWidth() / 2f && y < preDrawInfoY) {
                            // 在右边，当前y位置小于之前画的，则需要进行偏移
                            y = preDrawInfoY + (mPaint.getTextSize() + mYInterval) * mTitleLine;
                        } else if (x <= getWidth() / 2f && y > preDrawInfoY) {
                            // 在左边，当前y位置大于之前画的，则需要进行偏移
                            y = preDrawInfoY - (mPaint.getTextSize() + mYInterval) * mTitleLine;
                        } else {
                            // 与之前的y间距差太小
                            float intervalY = (mPaint.getTextSize() + mYInterval) * mTitleLine - Math.abs(y - preDrawInfoY);
                            if (x > getWidth() / 2f) {
                                y += intervalY;
                            } else {
                                y -= intervalY;
                            }
                        }
                        // 当y位置偏移过后，点的位置距离圆心小于r+20时，x轴需要进行偏移，扩大距离，避免绘制覆盖在圆环上面
                        if (Math.sqrt(Math.pow(getWidth() / 2f - x, 2) + Math.pow(getHeight() / 2f - y, 2)) < r + 20) {
                            float tempX = (float) Math.sqrt(Math.pow(r + 20, 2) - Math.pow(getHeight() / 2f - y, 2));
                            if (x > getWidth() / 2f) {
                                x = getWidth() / 2f + tempX;
                            } else {
                                x = getWidth() / 2f - tempX;
                            }
                        }
                    }
                }
            }
            path.lineTo(x, y);

            preDrawInfoX = x;
            preDrawInfoY = y;

            abs = (float) Math.abs(Math.sin(angleRadians) * 20);
            if (centerAngle >= -90 && centerAngle < 90) {
                // 向右
                x += 20 + abs;
            } else {
                // 向左
                x -= 20 + abs;
            }
            path.lineTo(x, y);
            canvas.drawPath(path, mPaint);
            path.reset();

            // 画文字
            mPaint.setTextSize(mTextSize);
            mPaint.setColor(mTextColor);
            mPaint.setStyle(Paint.Style.FILL);
            String percent = String.format(Locale.getDefault(), "%.02f%%", datum.value * 100 / mTotalValue);

            if (mTitleLine == 1) {
                // 合并成一行进行绘制
                textY = y + CanvasUtil.getDrawTextOffsetY(mPaint);
                if (centerAngle >= -90 && centerAngle < 90) {
                    // 向右
                    textX = x + 12;
                } else {
                    // 向左
                    textX = x - 12 - mPaint.measureText(percent + datum.name);
                }
                canvas.drawText(percent + datum.name, textX, textY, mPaint);
            } else {
                // 分两行
                textY = y - mPaint.getTextSize() / 2 - mYInterval / 2 + CanvasUtil.getDrawTextOffsetY(mPaint);
                if (centerAngle >= -90 && centerAngle < 90) {
                    // 向右
                    textX = x + 12;
                } else {
                    // 向左
                    textX = x - 12 - mPaint.measureText(percent);
                }
                canvas.drawText(percent, textX, textY, mPaint);

                textY = y + mPaint.getTextSize() / 2 + mYInterval / 2 + CanvasUtil.getDrawTextOffsetY(mPaint);
                if (centerAngle >= -90 && centerAngle < 90) {
                    // 向右
                    textX = x + 12;
                } else {
                    // 向左
                    textX = x - 12 - mPaint.measureText(datum.name);
                }
                canvas.drawText(datum.name, textX, textY, mPaint);
            }
        }
    }
}
